#include "StdAfx.h"
#include "Texture.h"



//-----------------------------------------------------------------------------
Texture::Texture(LPCTSTR filename)
:	texture	(0),
	width		(0),
	height	(0)
{
	glGenTextures	(1, &texture);
	glBindTexture	(GL_TEXTURE_2D, texture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	if(filename)
	{
		GraphicsFile tmp(filename);
		setData(tmp);
	}
}

//-----------------------------------------------------------------------------
Texture::Texture(const GraphicsFile &g)
:	texture	(0),
	width		(0),
	height	(0)
{
	glGenTextures	(1, &texture);
	glBindTexture	(GL_TEXTURE_2D, texture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	setData(g);
}

//-----------------------------------------------------------------------------
Texture::~Texture()
{
	glDeleteTextures(1, &texture);
}


//-----------------------------------------------------------------------------
void Texture::setData(const GraphicsFile &g)
{
	GLenum format;

	switch(g.getBitDepth())
	{
		case 4:	format = GL_LUMINANCE4;		break;
		case 8:	format = GL_LUMINANCE;		break;
		case 16:	format = GL_LUMINANCE16;	break;
		case 24:	format = GL_BGR_EXT;			break;
		case 32:	format = GL_BGRA_EXT;		break;
		default:	return;
	}

	setData(g.getWidth(), g.getHeight(), format, g.getData());
}

//-----------------------------------------------------------------------------
void Texture::setData(GLsizei w, GLsizei h, GLenum format, const BYTE *data)
{
	width  = w;
	height = h;

	if(data==NULL)								// if data is NULL, width and height can be changed without touching the texture data
		return;

	GLint internalFormat = format;
	GLenum type = GL_UNSIGNED_BYTE;
	switch(format)
	{
		case GL_LUMINANCE4:	type   = GL_BITMAP;
//		falls through
		case GL_LUMINANCE:	format = GL_LUMINANCE;
		break;

		case GL_BGRA_EXT:
		case GL_RGBA:			internalFormat = 4;
		break;

		default:					internalFormat = 3;
	}

	glBindTexture(GL_TEXTURE_2D, texture);
	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, format, type, data);
}


//-----------------------------------------------------------------------------
void Texture::draw(const RECT &r) const
{
	glBindTexture	(GL_TEXTURE_2D, texture);
	glBegin			(GL_TRIANGLE_STRIP);
	glTexCoord2s(0,1);	glVertex2i(r.left,  r.bottom);
	glTexCoord2s(1,1);	glVertex2i(r.right, r.bottom);
	glTexCoord2s(0,0);	glVertex2i(r.left,  r.top);
	glTexCoord2s(1,0);	glVertex2i(r.right, r.top);
	glEnd();
}

//-----------------------------------------------------------------------------
//	draw texture as rectangle, with the upper left corner / center at (x,y).
void Texture::draw(float x, float y, float scale, bool centered) const
{
	if(width==0||height==0)
		return;

	if(centered)
		scale *= 0.5f;

	float w = scale*width,
			h = scale*height,
			x2 = x+w,
			y2 = y+h;

	if(centered)
	{
		x -= w;
		y -= h;
	}

	glBindTexture	(GL_TEXTURE_2D, texture);
	glBegin			(GL_TRIANGLE_STRIP);
	glTexCoord2f(0.0f,1.0f);	glVertex2f(x,  y2);
	glTexCoord2f(1.0f,1.0f);	glVertex2f(x2, y2);
	glTexCoord2f(0.0f,0.0f);	glVertex2f(x,  y);
	glTexCoord2f(1.0f,0.0f);	glVertex2f(x2, y);
	glEnd();
}



//-----------------------------------------------------------------------------
TiledTexture::TiledTexture(LPCTSTR filename, wchar_t firstChar, unsigned numChars, unsigned numRows, float kerning)
:	t			(filename),
	char0		(firstChar),
	charCount(numChars),
	rows		(numRows),
	dx			(kerning * float(t.getWidth()) / float(charCount)),
	du			(1.0f / float(charCount)),
	dv			(1.0f / float(rows))
{};
//-----------------------------------------------------------------------------
TiledTexture::TiledTexture(const GraphicsFile &g, wchar_t firstChar, unsigned numChars, unsigned numRows, float kerning)
:	t			(g),
	char0		(firstChar),
	charCount(numChars),
	rows		(numRows),
	dx			(kerning * float(t.getWidth()) / float(charCount)),
	du			(1.0f / float(charCount)),
	dv			(1.0f / float(rows))
{};


//#define DEBUG_TILED_TEXTURE 1			// for checking placement of the chars in the texture

//-----------------------------------------------------------------------------
void TiledTexture::draw(wchar_t c, float x, float y, float scale, bool centered) const
{
	if(centered)
		scale *= 0.5f;

	float	w	= scale*t.getWidth()*du,
			h	= scale*t.getHeight()*dv,
			x2	= x+w,
			y2	= y+h;

	if(centered)
	{
		x -= w;
		y -= h;
	}

	c -= char0;
	wchar_t	col = c % charCount,
				row = c / charCount;
	float		u1  = du*(col),
				u2  = du*(col+1),
				v1  = dv*(row),
				v2  = dv*(row+1);

	t.bind();
	glBegin(GL_TRIANGLE_STRIP);
	glTexCoord2f(u1,v2);	glVertex2f(x,  y2);
	glTexCoord2f(u2,v2);	glVertex2f(x2, y2);
	glTexCoord2f(u1,v1);	glVertex2f(x,  y);
	glTexCoord2f(u2,v1);	glVertex2f(x2, y);
	glEnd();

#ifdef DEBUG_TILED_TEXTURE
		glDisable(GL_TEXTURE_2D);
		glBegin(GL_LINE_LOOP);
		glVertex2f(x,  y2);
		glVertex2f(x2, y2);
		glVertex2f(x2, y);
		glVertex2f(x,  y);
		glEnd();
		glEnable(GL_TEXTURE_2D);
#endif
}



//-----------------------------------------------------------------------------
void TiledTexture::drawString(const std::wstring &str, float x, float y, float scale, align::h hAlign, align::v vAlign) const
{
	float	w	= scale*t.getWidth()*du,
			h	= scale*t.getHeight(),
			sx	= scale*dx;

	if			(hAlign == align::right)		x -= sx*str.length();
	else if	(hAlign == align::centered)	x -= sx*str.length()*0.5f;

	if			(vAlign == align::bottom)		y -= h;
	else if	(vAlign == align::center)		y -= h*0.5f;

//----
//	draw all the chars
	t.bind();
	LPCWSTR s = str.c_str();
	for(int i = 0; s[i]; i++)
	{
		unsigned n = s[i] - char0;
		float	u1 = du*(n),
				u2 = du*(n+1);

		glBegin(GL_TRIANGLE_STRIP);
		glTexCoord2f(u1,1.0f);	glVertex2f(x,   y+h);
		glTexCoord2f(u2,1.0f);	glVertex2f(x+w, y+h);
		glTexCoord2f(u1,0.0f);	glVertex2f(x,   y);
		glTexCoord2f(u2,0.0f);	glVertex2f(x+w, y);
		glEnd();

#ifdef DEBUG_TILED_TEXTURE
		glDisable(GL_TEXTURE_2D);
		glBegin(GL_LINE_LOOP);
		glVertex2f(x,   y+h);
		glVertex2f(x+w, y+h);
		glVertex2f(x+w, y);
		glVertex2f(x,   y);
		glEnd();
		glEnable(GL_TEXTURE_2D);
#endif

		x += sx;
	}
}


//-----------------------------------------------------------------------------
void TiledTexture::drawNumber(int n, float x, float y, float scale, align::h hAlign, align::v vAlign, bool sign, unsigned minDigits) const
{
	std::wstringstream convert;

	if(sign||n<0)
	{
		wchar_t	plus	= L'+',
					minus	= L'-';
		if(charCount==12)
		{
			plus	= L'9'+1,					// convention: place + and - behind the digits
			minus	= L'9'+2;
		}

		if(n >= 0)	convert << plus;
		else			convert << minus;
	}

	convert << abs(n);

	std::wstring &str = convert.str();
	while(str.length() < minDigits)
			str = L"0" + str;

	drawString(str, x, y, scale, hAlign, vAlign);
}
